-
Notifications
You must be signed in to change notification settings - Fork 354
content: Use RealmStore.serverThumbnailFormats for thumbnails #1987
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
rajveermalviya
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @chrisbobbe! LGTM, just one small comment.
test/model/content_test.dart
Outdated
| --data-urlencode 'narrow=[{"operator":"sender", "operand":2187}, | ||
| --data-urlencode 'narrow=[{"operator":"sender", "operand":13313}, | ||
| {"operator":"stream", "operand":"test here"}, | ||
| {"operator":"topic", "operand":"content"}]' \ | ||
| {"operator":"topic", "operand":"Thumbnails"}]' \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left from debug?
This might've been done more simply by just adding the boolean value as a new field like `thumbnailAnimated` on ImagePreviewNode. But this value works closely with some structured data in thumbnail URL paths, here in image previews and also in the upcoming "inline images" feature, zulip#1913. So this new ImageThumbnailLocator class seemed like a helpful way to present the data to consumers.
b94e0fb to
7d51241
Compare
gnprice
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for taking care of this! Comments below.
| /// Use [ImageThumbnailLocatorExtension.resolve] to obtain a suitable URL | ||
| /// for the current UI need. | ||
| /// It may not work without adding authentication credentials to the request. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like information for the ImageThumbnailLocator doc.
| } | ||
|
|
||
| @override | ||
| int get hashCode => Object.hash(urlPath, hasAnimatedVersion); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In hashCode, seed the hash with the class name so that the hash doesn't collide with other objects that happen to also consist of a string and a bool:
| int get hashCode => Object.hash(urlPath, hasAnimatedVersion); | |
| int get hashCode => Object.hash('ImageThumbnailLocator', urlPath, hasAnimatedVersion); |
| thumbnail: ImageThumbnailLocator( | ||
| urlPath: '/user_uploads/thumbnail/2/ce/nvoNL2LaZOciwGZ-FYagddtK/image.jpg/840x560.webp', | ||
| hasAnimatedVersion: false, | ||
| ), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: can keep these a bit more compact:
| thumbnail: ImageThumbnailLocator( | |
| urlPath: '/user_uploads/thumbnail/2/ce/nvoNL2LaZOciwGZ-FYagddtK/image.jpg/840x560.webp', | |
| hasAnimatedVersion: false, | |
| ), | |
| thumbnail: ImageThumbnailLocator(hasAnimatedVersion: false, | |
| urlPath: '/user_uploads/thumbnail/2/ce/nvoNL2LaZOciwGZ-FYagddtK/image.jpg/840x560.webp'), |
| urlPath: '/user_uploads/thumbnail/2/9f/tZ9c5ZmsI_cSDZ6ZdJmW8pt4/2c8d985d.gif/840x560-anim.webp', | ||
| hasAnimatedVersion: true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm. From this URL path, it sounds like the given path is the animated version. That makes the name "has animated version" seem a bit misleading.
The parser shows the attribute name in the HTML is data-animated. The most direct translation of that would be to call this field just animated. How about we use that name?
| final String? thumbnailUrl; | ||
| final ImageThumbnailLocator? thumbnail; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it'd be helpful to split this commit:
- An NFC prep commit makes the change on this line, and the other changes that makes necessary, with the new class having only
urlPath. - Then a separate commit adds
hasAnimatedVersion(oranimatedper another comment).
There are a lot of places that change in boring ways just from moving this URL path out to the new class, so it'd make the substantive changes easier to read if they were in a separate commit from that.
| final store = PerAccountStoreWidget.of(context); | ||
| ThumbnailFormat? bestCandidate; | ||
|
|
||
| final animateIfSupported = animationMode.resolve(context); | ||
| if (hasAnimatedVersion && animateIfSupported) { | ||
| bestCandidate ??= _bestFormatOf(store.sortedAnimatedThumbnailFormats, | ||
| width: widthPhysicalPx, height: heightPhysicalPx); | ||
| } | ||
|
|
||
| bestCandidate ??= _bestFormatOf(store.sortedStillThumbnailFormats, | ||
| width: widthPhysicalPx, height: heightPhysicalPx); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: join up the bestCandidate computation as one stanza (and separate it from getting store)
| if (bestCandidate == null) { | ||
| // Odd if we'd need to fall back to the format encoded in [locator]'s path. | ||
| // Seems theoretically possible though: | ||
| // maybe this format isn't used now, for new uploads, | ||
| // but it was used in the past, including for this image. | ||
| return store.realmUrl.replace(path: urlPath); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is normal if there are no thumbnail formats at all, right?
In fact I think if this happens, it must be the case that there are no still thumbnail formats.
| return store.realmUrl.replace(path: urlPath); | ||
| } | ||
|
|
||
| final lastSlashIndex = urlPath.lastIndexOf('/'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These lines both assume that the URL string in urlPath is indeed just a path, and doesn't also contain a query and/or fragment.
I think it'd be reasonable for the API to guarantee that, but it doesn't appear to now (at https://zulip.com/api/message-formatting#images ). Without such a guarantee, a query component (though maybe not a fragment) would be a reasonable choice for this bit of API in isolation — e.g. Gravatar does that, as seen in our GravatarUrl.
(OTOH we do know it starts with a path component, because it starts with /u.)
So it'd be good to discuss that in #api documentation or #api design. Also to have the ImageThumbnailLocator constructor assert it, like it already does for the start of the path. A suitable check would be that there is no ? or # character.
| 'https://chat.example/user_uploads/thumbnail/1/2/a/pic.jpg/1000x2000.png'); | ||
| }); | ||
|
|
||
| testWidgets('animated version does not exist', (tester) async { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: probably clearest to put this test before its sibling — this seems like the simpler case to think about, and covers most of the interesting logic (and is surely the most common case)
Then the other test can focus just on what changes when hasAnimatedVersion is true.
| doCheck(tester, 250, 450, false, hasAnimatedVersion: false, | ||
| 'https://chat.example/user_uploads/thumbnail/1/2/a/pic.jpg/500x900.jpg'); | ||
| doCheck(tester, 300, 250, true, hasAnimatedVersion: false, | ||
| 'https://chat.example/user_uploads/thumbnail/1/2/a/pic.jpg/840x560.webp'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, why do these get different results? Both formats should be big enough for both these desired sizes, right?
… Ah, I see: it's because they're in physical pixels.
Would be good to have a comment highlighting that. 🙂 That's also one of the key points this test is making, so it's good to make it explicit.
Fixes #1936.